package net.xumf.support.common;

import lombok.extern.slf4j.Slf4j;
import net.xumf.support.converter.Converter;
import net.xumf.support.converter.PageConverter;
import net.xumf.support.enums.CodeEnum;
import net.xumf.support.exception.NotFoundDataRowInfoException;
import net.xumf.support.model.dto.PageDTO;
import net.xumf.support.model.vo.PageVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;

import javax.persistence.Id;
import java.lang.reflect.Field;
import java.util.Optional;

/**
 * 通用抽象类，封装了删除、修改、添加方法
 *
 * @param <R>  {@link CrudRepository} jpa增删改查的接口
 * @param <P>  对应表中的pojo对象
 * @param <ID> 对应表中的主键类型
 */
@Slf4j
public abstract class BaseServiceImpl<R extends PagingAndSortingRepository<P, ID>, P, ID>
        implements BaseService<P, ID> {

    @Autowired
    protected R repository;

    @Override
    public Optional<P> getById(ID id) {
        return repository.findById(id);
    }

    @Override
    public Iterable<P> getAll() {
        return repository.findAll();
    }

    @Override
    public <T extends PageDTO> PageVO getByPage(T pageDTO) {
        Pageable pageable = PageConverter.pageVOToPageable(pageDTO);
        Page<P> rolePage = repository.findAll(pageable);
        return PageConverter.pageToPageDTO(rolePage);
    }

    @Override
    public <S extends P> void update(S pojo) {
        repository.save(pojo);
    }

    @Override
    public <S extends P> P add(S pojo) {
        return repository.save(pojo);
    }

    @Override
    public void remove(ID pojoId) {
        repository.deleteById(pojoId);
    }

    @Override
    public void removeAll() {
        repository.deleteAll();
    }

    @SuppressWarnings("unchecked")
    private ID getIdByIdAnnotation(P p) {
        try {
            Field[] pFields = p.getClass().getDeclaredFields();
            for (Field field : pFields) {
                field.setAccessible(true);
                // 如果为主键id
                if (field.getAnnotation(Id.class) != null) {
                    // 获取id，并且获取id对应行数据
                    Object o = field.get(p);
                    if (o == null) {
                        return null;
                    } else {
                        return (ID) o;
                    }
                }
            }
        } catch (IllegalAccessException ignored) {
        }
        return null;
    }

    @Override
    public <S extends P> P dynamicSave(S s) {
        ID id = getIdByIdAnnotation(s);
        assert id != null : String.format("无法找到%s对象id", s.getClass().getName());
        Optional<P> pOptional = repository.findById(id);
        P oldP = pOptional.orElseThrow(() -> new NotFoundDataRowInfoException(CodeEnum.MODIFY_NOT_FOUND_ROW_ERROR));
        Converter.to(oldP, s, true);
        return repository.save(oldP);
    }


}
